/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */

package cgl.narada.transport.udp;

import java.util.Vector;

import cgl.narada.util.ByteUtilities;

/**
 * <p>
 * Title: UDPBigPackageHandler
 * </p>
 * <p>
 * Description: This file helps to send the bytes bigger than 64KB
 * </p>
 * 
 * @author Beytullah Yildiz
 * @version 1.0
 */

public class UDPBigPackageHandler {

    private UDPPackageCombine udppackagecombine;

    private UDPPackageDivide udppackagedivide;

    boolean receiver_debug = false;

    boolean sender_debug = false;

    String moduleName = "UDPBigPackageHandler";

    long lastuniquenumber;

    /**
     * Constructor
     */
    public UDPBigPackageHandler() {
    }

    public void shutdownServices() {
        udppackagecombine.shutdownServices();
    }

    /**
     * Initilize parameters for receiver
     * 
     * @param debug
     *            passed debugging parameter
     */
    public void initReceiver(boolean debug) {
        receiver_debug = debug;
        udppackagecombine = new UDPPackageCombine(debug);

        udppackagecombine.start();
    }

    /**
     * Initilize parameters for sender
     * 
     * @param debug
     *            passed debugging parameter
     */

    public void initSender(boolean debug) {
        udppackagedivide = new UDPPackageDivide();
        sender_debug = debug;

    }

    /**
     * Creates unique id for a big package The id is taken from the system
     * current time if it is equal previous one it is incremented 1
     * 
     * @return a long value
     */

    private long getUniqueNumber() {
        long unumber = System.currentTimeMillis();
        if (lastuniquenumber == unumber) {
            unumber = unumber + 1;
            lastuniquenumber = unumber;
        }
        return unumber;
    }

    /**
     * Receives a big chunk of byte and devides it to smaller than 64 KB byte
     * arrays
     * 
     * @param data
     *            received big chunk
     * @return vector of smaller bytes
     */
    public Vector createSmallPackVector(byte[] data) {
        UDPPackageDivide uph = new UDPPackageDivide();
        Vector pvector = new Vector();
        long uniquenumber = getUniqueNumber();
        uph.addJobsToJobVector(pvector, data, uniquenumber);
        return pvector;
    }

    /**
     * Composes a package to send
     * 
     * @param pvector
     *            Receives a vector of bytes
     * @return a package ready to send
     */
    public byte[] composePackage(Vector pvector) {
        UDPPackageDivide.PackageObject pobject = null;
        synchronized (pvector) {
            pobject = (UDPPackageDivide.PackageObject) pvector.get(0);
            pvector.remove(0);
        }

        long pnumber = pobject.getUniqueNumber();
        int wholepacksize = pobject.getWholePackSize();
        int startpoint = pobject.getStartPoint();
        int endpoint = pobject.getEndPoint();
        int packoffset = startpoint;
        int packsize = endpoint - startpoint;

        byte[] hdr_size = ByteUtilities.getBytes(packsize);
        byte[] hdr_number = ByteUtilities.getBytes(pnumber);
        byte[] hdr_whole = ByteUtilities.getBytes(wholepacksize);
        byte[] hdr_offset = ByteUtilities.getBytes(packoffset);
        byte[] sentarray = new byte[hdr_size.length + hdr_number.length
            + hdr_whole.length + hdr_offset.length + packsize + 1];

        sentarray[0] = (byte) 102;

        int offset = 1;
        System.arraycopy(hdr_size, 0, sentarray, offset, hdr_size.length);
        offset = offset + hdr_size.length;

        System.arraycopy(hdr_number, 0, sentarray, offset, hdr_number.length);
        offset = offset + hdr_number.length;

        System.arraycopy(hdr_whole, 0, sentarray, offset, hdr_whole.length);
        offset = offset + hdr_whole.length;

        System.arraycopy(hdr_offset, 0, sentarray, offset, hdr_offset.length);
        offset = offset + hdr_offset.length;

        byte[] load = pobject.getSendingBytes();
        System.arraycopy(load, packoffset, sentarray, offset, packsize);

        if (sender_debug) {

            System.out.println(moduleName + "sender packsize <" + packsize
                + ">  unique number <" + pnumber + "> total pack size <"
                + wholepacksize + "> offset <" + packoffset + ">");
        }

        return sentarray;
    }

    /**
     * Handles received packages, combines small packages
     * 
     * @param dataRecv
     *            Received package
     * @return byte array
     */
    public byte[] receivedPackages(byte[] dataRecv) {
        byte[] temp = new byte[4];
        System.arraycopy(dataRecv, 0, temp, 0, 4);
        int hdr_size = ByteUtilities.getInt(temp);
        byte[] temp1 = new byte[8];
        System.arraycopy(dataRecv, 4, temp1, 0, 8);
        long hdr_pnumber = ByteUtilities.getLong(temp1);
        System.arraycopy(dataRecv, 12, temp, 0, 4);
        int hdr_whole = ByteUtilities.getInt(temp);
        System.arraycopy(dataRecv, 16, temp, 0, 4);
        int hdr_offset = ByteUtilities.getInt(temp);

        byte[] data_recv = new byte[dataRecv.length - 20];
        byte[] returnedbyte = null;
        if (hdr_size == data_recv.length) {
            System.arraycopy(dataRecv, 20, data_recv, 0, data_recv.length);
            returnedbyte = udppackagecombine.recombinePack(hdr_pnumber,
                                                           hdr_whole,
                                                           hdr_offset,
                                                           data_recv);

            if (receiver_debug) {

                System.out.println(moduleName + "receiver packsize <"
                    + hdr_size + ">  unique number <" + hdr_pnumber
                    + "> total pack size <" + hdr_whole + "> offset <"
                    + hdr_offset + ">");

            }

        }
        return returnedbyte;

    }

    public static void main(String[] args) {
        UDPBigPackageHandler UDPBigPackageHandler1 = new UDPBigPackageHandler();
    }

}
